#pragma once
#include <iostream>
#include <string>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "log.hpp"

namespace TcpClient
{
    class Client;

    class context
    {
    public:
        context(Client *conClinet, pthread_t tid): _conClinet(conClinet), _tid(tid)
        {}

        Client* _conClinet;
        pthread_t _tid;
    };

    class Client
    {
    public:
        Client(const std::string &Serverip, const uint16_t &Serverport)
            : _Serverport(Serverport), _Serverip(Serverip)
        {}

        void init()
        {
            // 创建网络套接字
            _socket = socket(AF_INET, SOCK_STREAM, 0);
            if (_socket == -1)
            {
                logmessage(FATAL,  "socket failed");
                exit(1);
            }
            logmessage(SUCESS,  "socket sucess");

            // 客户端需要bind链接，但是不需要显示的链接，所以这里什么都不用干
            // 由操作系统进行的bind链接s
        }

        static void *readmessage(void *arvg)
        {
            context*ctx = static_cast<context*>(arvg);
            // 线程分离
            pthread_detach(pthread_self());
            int socket = ctx->_conClinet->_socket;
            
            // 开始接收信息
            while (1)
            {
                // 输入后，我们要等待服务器的返回,
                char readbuffer[1024];
                //ssize_t n = read(ctx->_conClinet->_socket , readbuffer, sizeof(readbuffer) - 1);
                ssize_t n = read(socket , readbuffer, sizeof(readbuffer) - 1);
                if (n == 0)
                {
                    std::cout << "服务端已经退出，什么也没有读到，我也退出了！" << std::endl;
                    break;
                }
                else
                {
                    readbuffer[n] = 0;
                    std::cout << "收到了服务端的返回#" << readbuffer << std::endl;
                    fflush(stdout);
                }
            }
            
            delete ctx;
        }

        void start()
        {
            // 开始建立链接
            struct sockaddr_in address;
            bzero(&address, sizeof(address));
            address.sin_family = AF_INET;
            address.sin_port = htons(_Serverport);
            address.sin_addr.s_addr = inet_addr(_Serverip.c_str());

            int n = connect(_socket, (struct sockaddr *)&address, sizeof(address));
            if (n == -1)
            {
                logmessage(FATAL, "connect failed");
                exit(5);
            }
            logmessage(SUCESS, "connect sucess");
            // 开始输入
            pthread_t tid;
            context* ctx = new context(this, tid);
            pthread_create(&tid, nullptr, readmessage, (void *)ctx);

            std::string msg;
            while (1)
            {
                usleep(10000);
                fprintf(stdout, "pleases enter #");
                fflush(stdout);
                std::getline(std::cin, msg);
                // std::cout << msg << std::endl;
                write(_socket, msg.c_str(), msg.size());
            }
        }

    private:
        std::string _Serverip;
        uint16_t _Serverport;
        int _socket;
    };
}